{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "13cd1c3e",
      "metadata": {
        "id": "13cd1c3e"
      },
      "source": [
        "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-1/agent-memory.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239417-lesson-7-agent-with-memory)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8c451ffd-a18b-4412-85fa-85186824dd03",
      "metadata": {
        "id": "8c451ffd-a18b-4412-85fa-85186824dd03"
      },
      "source": [
        "# Agent memory\n",
        "\n",
        "## Review\n",
        "\n",
        "Previously, we built an agent that can:\n",
        "\n",
        "* `act` - let the model call specific tools\n",
        "* `observe` - pass the tool output back to the model\n",
        "* `reason` - let the model reason about the tool output to decide what to do next (e.g., call another tool or just respond directly)\n",
        "\n",
        "![Screenshot 2024-08-21 at 12.45.32 PM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbab7453080e6802cd1703_agent-memory1.png)\n",
        "\n",
        "## Goals\n",
        "\n",
        "Now, we're going extend our agent by introducing memory."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "d2b4b45b-cbaa-41b1-b3ed-f6b0645be3f9",
      "metadata": {
        "id": "d2b4b45b-cbaa-41b1-b3ed-f6b0645be3f9"
      },
      "outputs": [],
      "source": [
        "%%capture --no-stderr\n",
        "%pip install --quiet -U langchain_google_genai langchain_core langgraph"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "2b0cfa99",
      "metadata": {
        "id": "2b0cfa99"
      },
      "outputs": [],
      "source": [
        "from google.colab import userdata\n",
        "GEMINI_API_KEY = userdata.get('GEMINI_API_KEY')"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "02eff247-a2aa-4f7a-8be1-73dfebfecc63",
      "metadata": {
        "id": "02eff247-a2aa-4f7a-8be1-73dfebfecc63"
      },
      "source": [
        "We'll use [LangSmith](https://docs.smith.langchain.com/) for [tracing](https://docs.smith.langchain.com/concepts/tracing)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "74ef2ff0",
      "metadata": {
        "id": "74ef2ff0"
      },
      "outputs": [],
      "source": [
        "from google.colab import userdata\n",
        "LANGCHAIN_API_KEY = userdata.get('LANGCHAIN_API_KEY')"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9c5f123b-db5d-4816-a6a3-2e4247611512",
      "metadata": {
        "id": "9c5f123b-db5d-4816-a6a3-2e4247611512"
      },
      "source": [
        "This follows what we did previously."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "46647bbe-def5-4ea7-a315-1de8d97c8288",
      "metadata": {
        "collapsed": true,
        "id": "46647bbe-def5-4ea7-a315-1de8d97c8288"
      },
      "outputs": [],
      "source": [
        "from langchain_google_genai import ChatGoogleGenerativeAI\n",
        "\n",
        "def multiply(a: int, b: int) -> int:\n",
        "    \"\"\"Multiply a and b.\n",
        "\n",
        "    Args:\n",
        "        a: first int\n",
        "        b: second int\n",
        "    \"\"\"\n",
        "    return a * b\n",
        "\n",
        "# This will be a tool\n",
        "def add(a: int, b: int) -> int:\n",
        "    \"\"\"Adds a and b.\n",
        "\n",
        "    Args:\n",
        "        a: first int\n",
        "        b: second int\n",
        "    \"\"\"\n",
        "    return a + b\n",
        "\n",
        "def divide(a: int, b: int) -> float:\n",
        "    \"\"\"Divide a and b.\n",
        "\n",
        "    Args:\n",
        "        a: first int\n",
        "        b: second int\n",
        "    \"\"\"\n",
        "    return a / b\n",
        "\n",
        "tools = [add, multiply, divide]\n",
        "llm = ChatGoogleGenerativeAI(model=\"gemini-1.5-flash\", api_key = GEMINI_API_KEY)\n",
        "llm_with_tools = llm.bind_tools(tools)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "a9092b40-20c4-4872-b0ed-be1b53a15ef3",
      "metadata": {
        "id": "a9092b40-20c4-4872-b0ed-be1b53a15ef3"
      },
      "outputs": [],
      "source": [
        "from langgraph.graph import MessagesState\n",
        "from langchain_core.messages import AIMessage, HumanMessage, SystemMessage\n",
        "\n",
        "# System message\n",
        "sys_msg = SystemMessage(content=\"You are a helpful assistant tasked with performing arithmetic on a set of inputs.\")\n",
        "\n",
        "# Node\n",
        "def assistant(state: MessagesState) -> MessagesState:\n",
        "   return {\"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])]}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "771123a3-91ac-4076-92c0-93bcd69cf048",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 266
        },
        "id": "771123a3-91ac-4076-92c0-93bcd69cf048",
        "outputId": "2a26229b-d837-4563-fa43-c04bd78ee934"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {}
        }
      ],
      "source": [
        "from langgraph.graph import START, StateGraph\n",
        "from langgraph.prebuilt import tools_condition, ToolNode\n",
        "from IPython.display import Image, display\n",
        "from langgraph.graph.state import CompiledStateGraph\n",
        "\n",
        "# Graph\n",
        "builder: StateGraph = StateGraph(MessagesState)\n",
        "\n",
        "# Define nodes: these do the work\n",
        "builder.add_node(\"assistant\", assistant)\n",
        "builder.add_node(\"tools\", ToolNode(tools))\n",
        "\n",
        "# Define edges: these determine how the control flow moves\n",
        "builder.add_edge(START, \"assistant\")\n",
        "builder.add_conditional_edges(\n",
        "    \"assistant\",\n",
        "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
        "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
        "    tools_condition,\n",
        ")\n",
        "builder.add_edge(\"tools\", \"assistant\")\n",
        "react_graph: CompiledStateGraph = builder.compile()\n",
        "\n",
        "# Show\n",
        "display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e830b7ae-3673-4cc6-8627-4740b7b8b217",
      "metadata": {
        "id": "e830b7ae-3673-4cc6-8627-4740b7b8b217"
      },
      "source": [
        "## Memory\n",
        "\n",
        "Let's run our agent, as before."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "596a71a0-1337-44d4-971d-f80c367bd868",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "596a71a0-1337-44d4-971d-f80c367bd868",
        "outputId": "503094e2-f421-4f75-af40-f84e1f49a132"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "Add 3 and 4.\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "Tool Calls:\n",
            "  add (2e7d6053-1ee3-494d-ba83-b61f06227e66)\n",
            " Call ID: 2e7d6053-1ee3-494d-ba83-b61f06227e66\n",
            "  Args:\n",
            "    a: 3.0\n",
            "    b: 4.0\n",
            "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
            "Name: add\n",
            "\n",
            "7\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "\n",
            "The answer is 7.\n"
          ]
        }
      ],
      "source": [
        "messages = [HumanMessage(content=\"Add 3 and 4.\")]\n",
        "messages = react_graph.invoke({\"messages\": messages})\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "92f8128c-f4a5-4dee-b20b-3245bd33f6b3",
      "metadata": {
        "id": "92f8128c-f4a5-4dee-b20b-3245bd33f6b3"
      },
      "source": [
        "Now, let's multiply by 2!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "b41cc1d7-e6de-4d86-8958-8cf7446f4c22",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "b41cc1d7-e6de-4d86-8958-8cf7446f4c22",
        "outputId": "34b1804f-8a9b-4def-a603-624dd0223532"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "Multiply that by 2.\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "\n",
            "Please provide me with the number you want to multiply by 2.\n"
          ]
        }
      ],
      "source": [
        "messages = [HumanMessage(content=\"Multiply that by 2.\")]\n",
        "messages = react_graph.invoke({\"messages\": messages})\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "26e65f3c-e1dc-4a62-b8ab-02b33a6ff268",
      "metadata": {
        "id": "26e65f3c-e1dc-4a62-b8ab-02b33a6ff268"
      },
      "source": [
        "We don't retain memory of 7 from our initial chat!\n",
        "\n",
        "This is because [state is transient](https://github.com/langchain-ai/langgraph/discussions/352#discussioncomment-9291220) to a single graph execution.\n",
        "\n",
        "Of course, this limits our ability to have multi-turn conversations with interruptions.\n",
        "\n",
        "We can use [persistence](https://langchain-ai.github.io/langgraph/how-tos/persistence/) to address this!\n",
        "\n",
        "LangGraph can use a checkpointer to automatically save the graph state after each step.\n",
        "\n",
        "This built-in persistence layer gives us memory, allowing LangGraph to pick up from the last state update.\n",
        "\n",
        "One of the easiest checkpointers to use is the `MemorySaver`, an in-memory key-value store for Graph state.\n",
        "\n",
        "All we need to do is simply compile the graph with a checkpointer, and our graph has memory!"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "qQ2pp4kld7_Q",
      "metadata": {
        "id": "qQ2pp4kld7_Q"
      },
      "source": [
        "# Transient State vs. Steady State\n",
        "\n",
        "In computing and system behavior, we often encounter two states: transient and steady.\n",
        "\n",
        "1. **Transient State**:\n",
        "   - **Definition**: Transient state refers to the moments right after a change occurs. It's a temporary, dynamic condition.\n",
        "   - **Example**: When you start a new chat session, your memory is transient—you're catching up, refreshing your context, and getting back into the conversation groove.\n",
        "\n",
        "2. **Steady State**:\n",
        "   - **Definition**: Steady state represents a stable, predictable condition. It's when a system settles into an equilibrium.\n",
        "   - **Example**: As our chat progresses and we remember details from earlier conversations, we move toward a steady state.\n",
        "\n",
        "Remember, in a single chat session (or graph execution), we experience both transient and steady states. Each interaction contributes to our overall understanding.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "637fcd79-3896-42e4-9131-e03b123a0a90",
      "metadata": {
        "id": "637fcd79-3896-42e4-9131-e03b123a0a90"
      },
      "outputs": [],
      "source": [
        "from langgraph.checkpoint.memory import MemorySaver\n",
        "memory: MemorySaver = MemorySaver()\n",
        "react_graph_memory: CompiledStateGraph = builder.compile(checkpointer=memory)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ff8fc3bf-3999-47cb-af34-06b2b94d7192",
      "metadata": {
        "id": "ff8fc3bf-3999-47cb-af34-06b2b94d7192"
      },
      "source": [
        "When we use memory, we need to specify a `thread_id`.\n",
        "\n",
        "This `thread_id` will store our memory location of graph states collection.\n",
        "\n",
        "Here is a cartoon:\n",
        "\n",
        "* The checkpointer write the state at every step of the graph\n",
        "* These checkpoints are saved in a thread\n",
        "* We can access that thread in the future using the `thread_id`\n",
        "\n",
        "![state.jpg](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e0e9f526b41a4ed9e2d28b_agent-memory2.png)\n",
        "\n",
        "![state.png](https://github.com/panaversity/learn-agentic-ai-fundamentals/blob/main/03_langchain_ecosystem/langgraph/course-notebooks/module-1/image.png)\n"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Specify a thread\n",
        "config1 = {\"configurable\": {\"thread_id\": \"1\"}}\n"
      ],
      "metadata": {
        "id": "ajK8ORW_s1f7"
      },
      "id": "ajK8ORW_s1f7",
      "execution_count": 8,
      "outputs": []
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "f722a1d6-e73c-4023-86ed-8b07d392278d",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "f722a1d6-e73c-4023-86ed-8b07d392278d",
        "outputId": "85c3739f-ce9a-4be6-de03-d01f94fc5b77"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "Add 3 and 4.\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "Tool Calls:\n",
            "  add (40401d12-dd4a-4d2f-8898-930c001a5572)\n",
            " Call ID: 40401d12-dd4a-4d2f-8898-930c001a5572\n",
            "  Args:\n",
            "    a: 3.0\n",
            "    b: 4.0\n",
            "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
            "Name: add\n",
            "\n",
            "7\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "\n",
            "The answer is 7.\n"
          ]
        }
      ],
      "source": [
        "\n",
        "\n",
        "# Specify an input\n",
        "messages = [HumanMessage(content=\"Add 3 and 4.\")]\n",
        "\n",
        "# Run\n",
        "messages = react_graph_memory.invoke({\"messages\": messages},config1)\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c91a8a16-6bf1-48e2-a889-ae04a37c7a2b",
      "metadata": {
        "id": "c91a8a16-6bf1-48e2-a889-ae04a37c7a2b"
      },
      "source": [
        "If we pass the same `thread_id`, then we can proceed from the previously logged state checkpoint!\n",
        "\n",
        "In this case, the above conversation is captured in the thread.\n",
        "\n",
        "The `HumanMessage` we pass (`\"Multiply that by 2.\"`) is appended to the above conversation.\n",
        "\n",
        "So, the model now know that `that` refers to the `The sum of 3 and 4 is 7.`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "ee38c6ef-8bfb-4c66-9214-6f474c9b8451",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ee38c6ef-8bfb-4c66-9214-6f474c9b8451",
        "outputId": "a65349fb-35c9-4824-9322-e76b1837402a"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "================================\u001b[1m Human Message \u001b[0m=================================\n",
            "\n",
            "Multiply that by 2.\n",
            "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
            "\n",
            "Please provide me with the number you would like to multiply by 2.\n"
          ]
        }
      ],
      "source": [
        "messages = [HumanMessage(content=\"Multiply that by 2.\")]\n",
        "messages = react_graph_memory.invoke({\"messages\": messages}, config1)\n",
        "for m in messages['messages']:\n",
        "    m.pretty_print()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c4b7774e-566f-4c92-9429-ed953bcacaa5",
      "metadata": {
        "id": "c4b7774e-566f-4c92-9429-ed953bcacaa5"
      },
      "source": [
        "## LangGraph Studio\n",
        "\n",
        "--\n",
        "\n",
        "**⚠️ DISCLAIMER**\n",
        "\n",
        "*Running Studio currently requires a Mac. If you are not using a Mac, then skip this step.*\n",
        "\n",
        "--\n",
        "\n",
        "Load the `agent` in the UI, which uses `module-1/studio/agent.py` set in `module-1/studio/langgraph.json`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6d72986c-ff6f-4f81-b585-d268e2710e53",
      "metadata": {
        "id": "6d72986c-ff6f-4f81-b585-d268e2710e53"
      },
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.1"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
